#include "RC5Decoder.h"


#define RC5_TOGGLE_MASK   0xF7FF
#define RC5X_TOGGLE_MASK  0xFFFF

RC5Decoder::RC5Decoder( ILoggerPtr logger, PublisherPtr publisher ) : BaseIrDecoder(logger, publisher)
{

}

bool RC5Decoder::process ( unsigned long * Data, size_t DataCount )
{
    DWORD i;

    if (!Data)
    {
        m_DetectState = DETECT_HEADER_PULSE;
        return false;
    }

    for (i = 0 ; i < DataCount ; i++)
    {
        DWORD Duration = Data[i] & PULSE_MASK;
        BOOL Pulse = ((Data[i] & PULSE_BIT) != 0);
        BOOL Ignored = TRUE;
        //DebugRC5("%s %d\n", Pulse ? "Pulse" : "Space", Duration);
        switch(m_DetectState)
        {
        case DETECT_HEADER_PULSE:
            if (Pulse)
            {
                if ((Duration >= 750) && (Duration <= 1100))
                {
                    m_DetectState = DETECT_HEADER_SPACE;
                    Ignored = FALSE;
                    
                    m_Bit = 13;
                    m_Code = 1 << m_Bit;
                    
                }
                else if ((Duration >= 1500) && (Duration <= 2000))
                {
                    m_DetectState = DETECT_DATA;
                    Ignored = FALSE;
                    m_Bit = 13;
                    m_Code = 1 << m_Bit;
                    m_HalfBit = 0;
                    
                }
            }
            break;
        case DETECT_HEADER_SPACE:
            if (!Pulse && (Duration >= 750) && (Duration <= 1100))
            {
                m_DetectState = DETECT_DATA;
                Ignored = FALSE;
                m_HalfBit = 0;
             
            }
            break;
        case DETECT_DATA:
            if (m_HalfBit == 0)
            {
                if (Pulse) 
                {
                    if (((Duration >= 750) && (Duration <= 1100)) ||
                        ((Duration >= 1500) && (Duration <= 2000)))
                    {
                        Ignored = FALSE;
                        m_HalfBit = (Duration >= 1500) ? 0 : 1;
                        m_Bit--;
                        m_Code |= 1 << m_Bit;
                        
                        if ((m_Bit == 0) ||
                            ((m_Bit == 1) && (Duration >= 1500)))
                        {
                            m_DetectState = DETECT_KEYCODE;
                        
                        }
                    }
                    else
                    {
                        // DebugRC5("Pulse error %d on bit %d\n", Duration, m_Bit);
                    }
                }
                else
                {
                    if (((Duration >= 750) && (Duration <= 1100)) ||
                        ((Duration >= 1500) && (Duration <= 2000)))
                    {
                        Ignored = FALSE;
                        m_HalfBit = (Duration >= 1500) ? 0 : 1;
                        m_Bit--;
                        //DebugRC5("DATA bit:%d code:%08X\n", m_Bit, m_Code);
                        if (m_Bit == 0)
                        {
                            m_DetectState = DETECT_KEYCODE;
                          //  DebugRC5("DETECT_KEYCODE code:%08X\n", m_Code);
                        }
                    }
                    else if ((m_Bit == 7) &&
                        (((Duration >= 4300) && (Duration <= 4700)) ||
                        ((Duration >= 5200) && (Duration <= 5600))))
                    {
                        Ignored = FALSE;
                        m_HalfBit = (Duration >= 5200) ? 0 : 1;
                        m_Code <<= 6;
                        m_Bit += 5;
                        //DebugRC5("DATA bit:%d code:%08X\n", m_Bit, m_Code);
                    }
                    else
                    {
                        //DebugRC5("Space error %d on bit %d\n", Duration, m_Bit);
                    }
                }
                break;
            }
            if ((Duration >= 750) && (Duration <= 1100))
            {
                Ignored = FALSE;
                m_HalfBit = 0;
                if ((m_Bit == 1) && (Pulse))
                {
                    m_DetectState = DETECT_KEYCODE;
                    //DebugRC5("DETECT_KEYCODE code:%08X\n", m_Code);
                }
            }
            else if ((m_Bit == 7) &&
                (((Duration >= 3400) && (Duration <= 3800)) ||
                ((Duration >= 4300) && (Duration <= 4700))))
            {
                Ignored = FALSE;
                m_HalfBit = (Duration >= 4300) ? 0 : 1;
                m_Code <<= 6;
                m_Bit += 6;
            }
            else
            {
                //Trace("Duration error %d on bit %d\n", Duration, m_Bit);
            }
            break;
        case DETECT_LEADING:
            if (Pulse) 
                break;
            if (Duration > 10000)
            {
                m_DetectState = DETECT_HEADER_PULSE;
                Ignored = FALSE;
            }
            break;
        }
        if (m_DetectState == DETECT_KEYCODE)
        {
            BOOL IsValid = FALSE;
            if (m_LastCode != m_Code)
            {
                IsValid = TRUE;
                m_LastCode = m_Code;
                m_LastTime = GetTickCount();
                m_RepeatCount = 0;
            }
			else
			{
				DWORD cur = GetTickCount();
				IsValid = TRUE;
				
				if (( m_RepeatCount == 0 ) && (cur - m_LastTime  < m_KbdFirstRepeat ))
				{
					
					m_RepeatCount++;
				}
				else if (( m_RepeatCount > 0 ) && ( cur - m_LastTime < m_KbdNextRepeats ))
				{					
					m_RepeatCount++;
				}
				else
				{
					// too slow.
					m_RepeatCount = 0;
				}

				m_LastTime = cur;
	
			}

            m_DetectState = DETECT_LEADING;

            if (IsValid)
            {
                if (m_Code > 0xFFFF)
                {
                    m_Code &= RC5X_TOGGLE_MASK;
                }
                else
                {
                    m_Code &= RC5_TOGGLE_MASK;
                }
                //Trace("GENERATE_RC5_KEYCODE code:%04X !!!\n", m_Code);
                //PostMessage(hWndRegistered, WM_USER, ID_RC5_KEYCODE, (m_RepeatCount << 16) | m_Code);
				// MceIrDecoded(ID_RC5_KEYCODE, (m_RepeatCount << 16) | m_Code);
				m_Publisher->call(ID_RC5_KEYCODE, m_Code, m_RepeatCount,"?");
				return true;
            }
        }
        if (Ignored && (m_DetectState != DETECT_LEADING) && (m_DetectState != DETECT_HEADER_PULSE))
        {
            m_DetectState = (Duration > 10000) ? DETECT_HEADER_PULSE : DETECT_LEADING;
            
        }
    }
	return false;
}